package mysql

import (
	"errors"
	"log"
	"os"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

var (
	logErr  = log.New(os.Stderr, "[mydb-error] ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
	logInfo = log.New(os.Stdout, "[mydb-info] ", log.Ldate|log.Lmicroseconds|log.Lshortfile)
)

/*
数据库连接结构体
*/
type MysqlGorm struct {
	Db     *gorm.DB
	Dsn    string
	Status int //连接状态
}

/*
构造函数
*/
func New() *MysqlGorm {
	db := new(MysqlGorm)
	return db
}

/*
连接数据库
*/
func (g *MysqlGorm) ConnectMysql(dbConfig string) error {
	go func() {
		g.Reconnect(dbConfig)
	}()
	return g.Connect(dbConfig)
}

/*
连接数据库
*/
func (g *MysqlGorm) Connect(dbConfig string) error {
	g.Dsn = dbConfig
	db, err := gorm.Open(mysql.Open(g.Dsn), &gorm.Config{
		Logger: logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags),
			logger.Config{
				SlowThreshold: time.Duration(500) * time.Millisecond, // 设置慢查询的阈值为500ms
				LogLevel:      logger.Warn,                           // 设置日志级别为警告
				Colorful:      true,                                  // 使日志带颜色
			},
		),
	})
	if err != nil {
		g.Db = nil
		g.Status = 0
		logErr.Println(err)
		return err
	}
	g.Db = db
	g.Status = 1
	logInfo.Println(">> mysql connected")
	return nil
}

/*
监测、重连数据库
*/
func (g *MysqlGorm) Reconnect(dbConfig string) error {
	for {
		time.Sleep(time.Second * 10)
		if g.Status != 1 {
			g.Connect(dbConfig)
		}
	}
}

var methodList = make([]interface{}, 0)

func RegMethod(m interface{}) {
	methodList = append(methodList, m)
}

type DataBase interface {
	DB() *gorm.DB
	CheckDB() error
	AutoMigrate(interface{}) error
	Find(interface{}) error
	Create(interface{}) error
	Delete(interface{}) error
	Updates(interface{}) error
	Save(interface{}) error
}

const ErrGormHead = "[ErrGorm]"

var (
	Err_DBNotConnect = errors.New(ErrGormHead + "database is not connect")
)

func (g *MysqlGorm) DB() *gorm.DB {
	// return g.Db.Debug() //TODO 打开 sql debug 模式
	return g.Db
}

func (g *MysqlGorm) CheckDB() error {
	if g.Db == nil {
		return Err_DBNotConnect
	}

	return nil
}

func (g *MysqlGorm) AutoMigrate(v interface{}) error {
	if g.Db == nil {
		return Err_DBNotConnect
	}

	g.Db.AutoMigrate(v)

	return nil
}

func (g *MysqlGorm) Find(v interface{}) error {
	if g.Db == nil {
		return Err_DBNotConnect
	}

	// g.Db.AutoMigrate(v)

	if db := g.Db.Find(v); db.Error != nil {
		return db.Error
	}

	return nil
}

func (g *MysqlGorm) Create(v interface{}) error {
	if g.Db == nil {
		return Err_DBNotConnect
	}

	if db := g.Db.Create(v); db.Error != nil {
		return db.Error
	}

	return nil
}

func (g *MysqlGorm) Delete(v interface{}) error {
	if g.Db == nil {
		return Err_DBNotConnect
	}

	if db := g.Db.Delete(v); db.Error != nil {
		return db.Error
	}

	return nil
}

func (g *MysqlGorm) Updates(v interface{}) error {
	if g.Db == nil {
		return Err_DBNotConnect
	}

	if db := g.Db.Updates(v); db.Error != nil {
		return db.Error
	}

	return nil
}

func (g *MysqlGorm) Save(v interface{}) error {
	if g.Db == nil {
		return Err_DBNotConnect
	}

	if db := g.Db.Save(v); db.Error != nil {
		return db.Error
	}

	return nil
}
